-- 匹配列表
-- Author: Colocasia
-- Date: 2018-08-21

local skynet = require 'skynet';
local tool = require 'tool';
local table = require 'us.table';

-- 常量
local ENUM_MATCH = require 'match_const';
local ENUM_GAME  = require 'game_const';

-- 常用函数
local skynet_time = skynet.time;
local table_merge = table.merge;
local table_clone = table.clone;
local table_foreach = table.foreach;
local table_sum = table.sum;

-- 匹配列表
local match_list = {
    guid    = '',                       -- 匹配列表GUID
    server  = '',                       -- 匹配列表服务器
    service = '',                       -- 匹配列表地址
    type    = ENUM_GAME.TYPE.PVE,       -- 匹配的类型
    game    = ENUM_GAME.LEVEL.DEMO,     -- 匹配的游戏
    count   = 2,                        -- 玩家人数
    score   = {},                       -- 匹配分数
    level   = 0,                        -- 等级要求
    update  = 0,                        -- 更新时间
    teams   = {},                       -- 队伍列表
}

local M = {}


---扩大匹配范围时间
local MATCH_ENLARGE_TIME    = 120;
local MATCH_ENLARGE_SCORE   = 10;


---创建一个匹配队列
function M.create(params)
    local ret = {
        guid = tool:guid(),
        server = params.server,
        service = params.service,
        type = params.type,
        game = params.game,
        count = params.count,
        score = params.score,
        level = params.level,
        update = skynet_time() + ENUM_MATCH.LIST_TIMEOUT,
    }
    return table_merge({table_clone(match_list), ret});
end


---检查分数是否符合条件
function M.check_score(list, player)
    local cond_score = list.score
    if not cond_score or #cond_score == 0 then
        return true
    end
 
    local min_scroe = cond_score[1] or 0;
    local max_scroe = cond_score[2] or 0;

    if player.score > max_scroe or player.score < min_scroe then
        return false
    end

    return true
end


---检查等级是否符合条件
function M.check_level(list, player)
    return player.level and player.level >= list.level;
end


---检查匹配地图的类型
function M.check_type(list, player)
    return player.game and player.game == list.game;
end


---检查条件是否符合
function M.check(list, team)
    for _, player in ipairs(team.players) do
        if not M.check_type(list, player) then
            return false
        end
    
        if not M.check_level(list, player) then
            return false;
        end
    
        if not M.check_score(list, player) then
            return false;
        end
    end
    return true
end


---弹出匹配队列的一个队伍
local function _pop_team(t)
    local teams_count = #t;
    local teams_idx = 1;
    local team_idx = 0;
    return function()
        local team_list = t[teams_idx];
        local team_cout = #team_list;
        if team_idx < team_cout then
            team_idx = team_idx + 1;
            return team_list[team_idx]
        else
            teams_idx = teams_idx + 1;
            if teams_idx <= teams_count then
                team_idx = 1;
                return t[teams_idx][team_idx];
            end
        end
    end
end
---匹配列表弹出队伍
function M.pop_teams(list)
    return _pop_team(list.teams);    
end


---队伍推出匹配列表
function M.exit(team)
    if not team then return end

    -- mark: 需要进行玩家解锁的操作
    table_foreach(team.players, function(player)

    end)
    return team;
end


---获取空位数量
function M.empty_count(list)
    local count = 0;
    local index = 0;
    for i, teams in ipairs(list.teams) do
        -- pve时只用匹配一个队列
        if ENUM_GAME.TYPE.PVE == list.type and i > 1 then
            break;
        end
        -- 计算单个队列的人数
        local _count = list.count - table_sum(teams, function(info)
            return info.count;
        end)
        -- 取出空位最多的一个team
        if _count > count then
            count = _count;
            index = i;
        end
    end
    return count, index;
end


---匹配列表是否满员
function M.is_full(list)
    return 0 == M.empty_count(list);
end


---尝试匹配一个玩家
function M.try(list, team)
    if not team then return false end

    local team_count = #team.player;
    if team_count < 1 then return false end

    -- 检查是否扩大范围
    M.check_enlarge(list)

    -- 检查人数是否可以添加
    local empty_count, idx = M.empty_count(list);
    if empty_count < team_count then return false end

    -- 检查玩家
    if not M.check(list, team) then return false end
    return M.add(list, team, idx);
end


---获取一个队伍的匹配信息
function M.get_match_info(team)
    if not team then return end
    local info = {
        server      = team.server,
        service     = team.service,
        team_guid   = team.guid,
        count       = #team.players,
    }
    return info;
end


---添加队伍进匹配列表
function M.add(list, team, idx)
    idx = idx or 1;

    -- 添加队伍进匹配列表
    list.teams[idx] = list.teams[idx] or {}
    local info = M.get_match_info(team)
    table.insert(list.teams[idx], info);

    -- mark: 需要进行玩家锁定的操作
    table_foreach(team.players, function(player, guid)

    end)

    return true;
end


---检查是否扩大
function M.check_enlarge(list)
    local now = os.time();
    local update = list.update;
    if 0 == list.update then
        list.update = now;
    elseif now - list.update > MATCH_ENLARGE_TIME then
        list.update = now;
        M.enlarge(list);
    end
end


---扩大条件的匹配范围
function M.enlarge(list)
    if list.score[1] then
        list.score[1] = math.max(0, (list.score[1] - MATCH_ENLARGE_SCORE))
    end

    local max_scroe = list.score[2] or 0;
    list.score[2] = max_scroe + MATCH_ENLARGE_SCORE;
end


---缩小条件的匹配范围
function M.shrink(list)
    if list.score[2] then
        list.score[2] = math.max(0, (list.score[2] - MATCH_ENLARGE_SCORE))
    end

    local max_scroe = list.score[1] or 0;
    list.score[1] = max_scroe + MATCH_ENLARGE_SCORE;
end

return M;
